/*
* ////////////////////////////////////////////////
*
* 开发者：AZPEP
* 友情链接：
*	-	B站：		零分的考卷			https://space.bilibili.com/257391258
*	-	Github：	AZPEP-BiliBili		https://github.com/AZPEP-BiliBili
*	-	Gitee：		AZPEP_BiliBili		https://gitee.com/AZPEP_BiliBili
*
* CopyRight AZPEP
*
* ////////////////////////////////////////////////
*/

//#include "stdafx.h" 
#include <iostream>

#include <string>
#include <sstream>
#include <cstring>

#include <locale>
#include <codecvt>

#include <fstream>
#include "pch.h"
#include "Struct.h"
#include "GetStr.h"
#include "WriteLog.h"
#include <fstream>
#include <iostream>

#include <comutil.h>  
using namespace std;
#pragma comment(lib, "comsuppw.lib")

inline std::string to_byte_string(const std::wstring& input);
void PrintWstring(std::wstring str);
vector<std::wstring> wsplitByN(std::wstring wstr);

typedef struct LogInfo {
	/// <summary>
	/// 日志服务句柄
	/// </summary>
	ASTLOG_HANDLE Handle;

	/// <summary>
	/// 日志文件路径
	/// </summary>
	std::wstring LogFilePath;
	/*
		/// <summary>
		/// Log文件输出流
		/// </summary>
		std::ofstream* LogFileOfStream = new std::ofstream();
		*/
		/// <summary>
		/// 检查日志是否启动
		/// </summary>
	bool IsLogServiceStart = false;

	/// <summary>
	/// 打印到日志
	/// </summary>
	bool PrintToConsole;

	/// <summary>
	/// 写入日志文件
	/// </summary>
	bool WriteToLog;

	/// <summary>
	/// 启用回调函数
	/// </summary>
	bool EnableCallBackFunction;

	/// <summary>
	/// 回调函数
	/// </summary>
	AstLogCallBackFuncW CallBackFunction;

}LogInfo;

/// <summary>
/// 获取日志结构体
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <returns>成功返回结构体指针，失败返回空指针</returns>
LogInfo* GetLogServiceHandle(
	ASTLOG_HANDLE Handle
);


/// <summary>
/// 输出日志
/// </summary>
/// <param name="LT">日志类型</param>
/// <param name="PrintToConsole">打印到日志</param>
/// <param name="WriteToLogFile">写入到日志文件</param>
/// <param name="Text">欲打印的文本</param>
/// <returns>成功返回true，失败返回false</returns>
bool PrintLogW(
	LogType LT,
	LogInfo* LI,
	bool PrintToConsole,
	bool WriteToLogFile,
	std::wstring Text
);


/// <summary>
/// 输出系统日志，注意：该函数不导出！
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <param name="Message">欲输出的内容</param>
/// <returns>成功返回true，失败返回false，可用GetLastError()获取错误代码</returns>
EXTERN_C bool AstLog_WriteLogW(
	ASTLOG_HANDLE Handle,
	std::wstring Text
) {
	//日志服务不存在或未启用，设置错误代码，返回false
	switch (AstLog_CheckHandleAvaiable(Handle)) {
	case 0:
		break;
	case 1:
		SetLastError(ASTLOG_ERROR_SERVICE_STOPPED);
		return false;
		break;
	case -1:
		SetLastError(ASTLOG_ERROR_SERVICE_HANDLE_NOT_FOUND);
		return false;
		break;
	}

	//指向日志的指针
	LogInfo* LI = GetLogServiceHandle(Handle);
	if (LI == nullptr) return false;			//获取失败，返回

	//输出日志
	return PrintLogW(
		__LOG,
		LI,
		LI->PrintToConsole,
		LI->WriteToLog,
		Text
	);


}

/// <summary>
/// 输出调试日志
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <param name="Message">欲输出的内容</param>
/// <returns>成功返回true，失败返回false，可用GetLastError()获取错误代码</returns>
EXTERN_C bool AstLog_WriteDebugW(
	ASTLOG_HANDLE Handle,
	std::wstring Text
) {
#ifdef _DEBUG
	//日志服务不存在或未启用，设置错误代码，返回false
	switch (AstLog_CheckHandleAvaiable(Handle)) {
	case 0:
		break;
	case 1:
		SetLastError(ASTLOG_ERROR_SERVICE_STOPPED);
		return false;
		break;
	case -1:
		SetLastError(ASTLOG_ERROR_SERVICE_HANDLE_NOT_FOUND);
		return false;
		break;
	}

	//指向日志的指针
	LogInfo* LI = GetLogServiceHandle(Handle);
	if (LI == nullptr) return false;			//获取失败，返回

	//输出日志
	return PrintLogW(
		__DEBUG,
		LI,
		LI->PrintToConsole,
		LI->WriteToLog,
		Text
	);
#else
	return true;
#endif
}

/// <summary>
/// 输出消息日志
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <param name="Message">欲输出的内容</param>
/// <returns>成功返回true，失败返回false，可用GetLastError()获取错误代码</returns>
EXTERN_C bool AstLog_WriteMessageW(
	ASTLOG_HANDLE Handle,
	std::wstring Text
) {
	//日志服务不存在或未启用，设置错误代码，返回false
	switch (AstLog_CheckHandleAvaiable(Handle)) {
	case 0:
		break;
	case 1:
		SetLastError(ASTLOG_ERROR_SERVICE_STOPPED);
		return false;
		break;
	case -1:
		SetLastError(ASTLOG_ERROR_SERVICE_HANDLE_NOT_FOUND);
		return false;
		break;
	}

	//指向日志的指针
	LogInfo* LI = GetLogServiceHandle(Handle);
	if (LI == nullptr) return false;			//获取失败，返回

	//输出日志
	return PrintLogW(
		__MESSAGE,
		LI,
		LI->PrintToConsole,
		LI->WriteToLog,
		Text
	);
}

/// <summary>
/// 输出警告日志
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <param name="Message">欲输出的内容</param>
/// <returns>成功返回true，失败返回false，可用GetLastError()获取错误代码</returns>
EXTERN_C bool AstLog_WriteWarningW(
	ASTLOG_HANDLE Handle,
	std::wstring Text
) {
	//日志服务不存在或未启用，设置错误代码，返回false
	switch (AstLog_CheckHandleAvaiable(Handle)) {
	case 0:
		break;
	case 1:
		SetLastError(ASTLOG_ERROR_SERVICE_STOPPED);
		return false;
		break;
	case -1:
		SetLastError(ASTLOG_ERROR_SERVICE_HANDLE_NOT_FOUND);
		return false;
		break;
	}

	//指向日志的指针
	LogInfo* LI = GetLogServiceHandle(Handle);
	if (LI == nullptr) return false;			//获取失败，返回

	//输出日志
	return PrintLogW(
		__WARNING,
		LI,
		LI->PrintToConsole,
		LI->WriteToLog,
		Text
	);
}

/// <summary>
/// 输出错误日志
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <param name="Message">欲输出的内容</param>
/// <returns>成功返回true，失败返回false，可用GetLastError()获取错误代码</returns>
EXTERN_C bool AstLog_WriteErrorW(
	ASTLOG_HANDLE Handle,
	std::wstring Text
) {
	//日志服务不存在或未启用，设置错误代码，返回false
	switch (AstLog_CheckHandleAvaiable(Handle)) {
	case 0:
		break;
	case 1:
		SetLastError(ASTLOG_ERROR_SERVICE_STOPPED);
		return false;
		break;
	case -1:
		SetLastError(ASTLOG_ERROR_SERVICE_HANDLE_NOT_FOUND);
		return false;
		break;
	}

	//指向日志的指针
	LogInfo* LI = GetLogServiceHandle(Handle);
	if (LI == nullptr) return false;			//获取失败，返回

	//输出日志
	return PrintLogW(
		__ERROR,
		LI,
		LI->PrintToConsole,
		LI->WriteToLog,
		Text
	);
}

/// <summary>
/// 输出日志
/// </summary>
/// <param name="LT">日志类型</param>
/// <param name="PrintToConsole">打印到日志</param>
/// <param name="WriteToLogFile">写入到日志文件</param>
/// <param name="Text">欲打印的文本</param>
/// <returns>成功返回true，失败返回false</returns>
bool PrintLogW(
	LogType LT,
	LogInfo* LI,
	bool PrintToConsole,
	bool WriteToLogFile,
	std::wstring Text
) {
	WORD OldConsoleColor;						// 原控制台字符颜色
	WORD ConsoleColor;							// 现控制台字符颜色
	std::wstring wsLT;							// 字符串类型的日志类型
	std::wstring NowDate = LogGetDateString();	// 当前时间

	for (int i = 0; i < Text.size(); i++) {
		wchar_t wc = Text[i];
		if (wc == L'\n') {
			std::vector<std::wstring> wsl = wsplitByN(Text);
			for (int j = 0; j < wsl.size(); j++) {
				std::wstring wstr = wsl[j];
				PrintLogW(
					LT,
					LI,
					PrintToConsole,
					WriteToLogFile,
					wstr
				);
			}
			return true;
		}
	}
	// 设置打印字符类型
	switch (LT) {
	case __LOG:
		wsLT = L"[  LOG  ]";
		ConsoleColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;  //白色
		break;

	case __DEBUG:
		wsLT = L"[ DEBUG ]";
		ConsoleColor = FOREGROUND_GREEN | FOREGROUND_INTENSITY; //亮绿色
		break;

	case __MESSAGE:
		wsLT = L"[MESSAGE]";
		ConsoleColor = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;  //青色
		break;

	case __WARNING:
		wsLT = L"[WARNING]";
		ConsoleColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; //黄色
		break;

	case __ERROR:
		wsLT = L"[ ERROR ]";
		ConsoleColor = FOREGROUND_RED | FOREGROUND_INTENSITY; //亮红色
		break;

	}

	//组装字符串
	//std::wstringstream wssS{ NowDate + wsLT + Text };
	std::wstring wssS{ NowDate + wsLT + Text + L"\n" };

#ifdef _DEBUG
	OutputDebugStringW(wssS.c_str());
#endif

	//打印字符串
	if (PrintToConsole) {
		HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
		SetConsoleTextAttribute(hCon, ConsoleColor);
		//wcout << wssS << L"\n";
		//cout << to_byte_string(wssS) << "\n";
		PrintWstring(wssS);
		SetConsoleTextAttribute(hCon, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
	}
	//写入到文件
	if (WriteToLogFile) {
		/*
		std::ofstream LogFileOfStream{ LI->LogFilePath,ios::app | ios::out };
		LogFileOfStream << wssS.c_str();
		LogFileOfStream.close();
		*/
		_wsetlocale(0, L"chs");
		FILE* file = _wfopen(LI->LogFilePath.c_str(), L"a,ccs=UTF-8");
		fwprintf(file, wssS.c_str());
		fclose(file);
	}

	//执行回传函数
	if (LI->EnableCallBackFunction) {
		LI->CallBackFunction((AstLogType)LT, (*new std::wstring{ wssS + L"\n"}).c_str());
	}

	return true;
}


// convert wstring to string 
inline std::string to_byte_string(const std::wstring& input)
{
	_bstr_t t = input.c_str();
	char* pchar = (char*)t;
	std::string result = pchar;
	return result;
}

//日志结构体集合
std::vector<LogInfo*> LogList_2 = *new std::vector<LogInfo*>;

//日志句柄序号
ASTLOG_HANDLE LogIndex = 25000;

/// <summary>
/// 通过Handle删除LogInfo结构体
/// </summary>
/// <param name="Handle"></param>
/// <returns>成功返回true，失败返回false</returns>
bool DeleteStructByHandle(
	ASTLOG_HANDLE Handle
) {
	for (auto iter = LogList_2.begin(); iter != LogList_2.end(); iter++) {
		if ((*iter)->Handle = Handle) {
			//擦除数据
			(*iter)->IsLogServiceStart = false;		//关闭服务，防止有讯号进入
			(*iter)->EnableCallBackFunction = false;
			(*iter)->CallBackFunction = NULL;

			//(*iter)->LogFileOfStream->close();		//解除文件锁
			(*iter)->LogFilePath = L"";				//清空日志路径

			//执行到这里这套日志结构体就报废了

			//擦除结构体
			LogList_2.erase(iter);
			return true;
		}
	}

	return false;
}

/// <summary>
/// 添加日志结构体
/// </summary>
/// <param name="LogFilePath">日志文件路径</param>
/// <param name="PrintToConsole">打印到日志</param>
/// /// <param name="CallBackFunction">设置回传函数，可为NULL</param>
/// <returns>成功返回句柄，失败返回0</returns>
ASTLOG_HANDLE AppendStruct(
	std::wstring LogFilePath,
	bool PrintToConsole,
	AstLogCallBackFuncW CallBackFunction
) {
	try {
		//添加新的结构体
		LogList_2.push_back(new LogInfo());

		//设置Handle
		LogIndex++;
		LogList_2[LogList_2.size() - 1]->Handle = LogIndex;

		//回传函数
		if (CallBackFunction != NULL) {
			LogList_2[LogList_2.size() - 1]->EnableCallBackFunction = true;
			LogList_2[LogList_2.size() - 1]->CallBackFunction = CallBackFunction;
		}
		else {
			LogList_2[LogList_2.size() - 1]->EnableCallBackFunction = false;
		}

		//其他基本设置
		LogList_2[LogList_2.size() - 1]->LogFilePath = LogFilePath;
		LogList_2[LogList_2.size() - 1]->PrintToConsole = PrintToConsole;


		if (LogFilePath == L"") {
			LogList_2[LogList_2.size() - 1]->WriteToLog = false;
		}
		else {
			/*
			//文件输出流
			LogList_2[LogList_2.size() - 1]->LogFileOfStream->open(LogFilePath, std::ios::app | std::ios::out);
			*/
			LogList_2[LogList_2.size() - 1]->WriteToLog = true;
		}
		//启动日志
		LogList_2[LogList_2.size() - 1]->IsLogServiceStart = true;

		return LogList_2[LogList_2.size() - 1]->Handle;
	}
	catch (std::string errInfo) {
		return 0;
	}
}

/// <summary>
/// 获取日志结构体
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <returns>成功返回结构体指针，失败返回空指针</returns>
LogInfo* GetLogServiceHandle(
	ASTLOG_HANDLE Handle
) {

	//遍历查找
	for (int i = 0; i < LogList_2.size(); i++) {
		if (LogList_2[i]->Handle == Handle) return LogList_2[i];
	}
	return nullptr;
}

/// <summary>
/// 查看日志句柄是否可用
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <returns>存在且已启用返回0，存在但未启用返回1，不存在返回-1</returns>
EXTERN_C DWORD AstLog_CheckHandleAvaiable(
	ASTLOG_HANDLE Handle
) {
	//遍历查找
	for (auto iter = LogList_2.begin(); iter != LogList_2.end(); iter++) {

		//查找打了，判断是否启用
		if ((*iter)->Handle == Handle) {

			//启用，返回0
			if ((*iter)->IsLogServiceStart) return 0;

			//没启用，返回1
			else return 1;
		}
	}

	//没查找到，返回-1
	return -1;
}

/// <summary>
/// 获取日志文件路径
/// </summary>
/// <param name="Handle">日志句柄</param>
/// <returns>若日志服务未启动，返回“”；若日志服务已启动则返回日志文件路径</returns>
EXTERN_C std::wstring AstLog_GetLogFilePath(
	ASTLOG_HANDLE Handle
) {
	//日志服务未启用，返回“”
	if (AstLog_CheckHandleAvaiable(Handle) != 0) {
		return L"";
	}

	//指向日志的指针
	LogInfo* LI = GetLogServiceHandle(Handle);
	if (LI == nullptr) return L"";			//获取失败，返回

	return LI->LogFilePath;
}

/// <summary>
/// 停止所有的日志服务
/// </summary>
void StopAllLogServices() {
	while (LogList_2.size() != 0) {
		AstLog_StopService(LogList_2[1]->Handle);
	}
}

void PrintWstring(std::wstring str) {
	setlocale(LC_ALL, "chs");
	wprintf_s(L"%s", str.c_str());

}

vector<std::wstring> wsplitByN(std::wstring wstr) {
	vector<std::wstring> wstrL;

	int number = 0;
	wstrL.push_back(L"");
	for (int i = 0; i < wstr.size(); i++) {
		wchar_t wc = wstr[i];

		if (wc == L'\n') { wstrL.push_back(L""); number++; }
		else wstrL[number] += wc;
	}

	return wstrL;
}